import { Injectable } from '@nestjs/common';
import { numToHex, strToHex } from 'src/util';

import * as mqtt from 'mqtt'
import { ConfigService } from '@nestjs/config';
import { CRC } from 'crc-full';

interface ChargeParams {
    portNo:number;
    orderId:number;
    strategyType:number;
    amount?:number;
    openDoorPassword?:string;
}

@Injectable()
export class GatewayService {
	private crc:CRC;
    private client:mqtt.MqttClient;
    private chargeTopic:string;
    private addChargeTopic:string;
    private stopChargeTopic:string;
    constructor(
        private configService:ConfigService
    ) {
		
		this.crc = new CRC("CRC16_XMODEM", 16, 0x1021, 0x0000, 0x0000, false, false);
		
		
        const conf = this.configService.get('mqtt')

        this.chargeTopic = conf.topic.charge
        this.addChargeTopic = conf.topic.addCharge
        this.stopChargeTopic = conf.topic.stopCharge

        this.client = mqtt.connect(conf.options)
        this.client.on('disconnect', () => {
            console.log('mqtt重连')
            this.client.reconnect()
        }).on('error', error => {
            console.log(conf.options)
            console.log(error)
        }).on('connect', () => {
            console.log('mqtt 链接成功')
        })
    }

    private send(deviceId:string, type:1|2, topic:string, str:string) :Promise<boolean>{
        deviceId = strToHex(deviceId, 40)
        let msg = '2878000' + type
        let d = new Date()
        let time = d.getTime()
        msg += numToHex(Math.floor(time / 1000), 8)
        msg += numToHex(time % 1000, 4)

        let followData = '00' + '0000000000000000' + deviceId + str; // + '0000' + '1555'
        let length = numToHex(followData.length / 2 + 4, 4)
		
		msg += (length + followData)
		
		msg += (this.crc.compute(Buffer.from(msg, 'hex')).toString(16))


        let message = {
            deviceId : deviceId,
            body : msg + '1555'
        }

        return new Promise((resolve, reject) => {
            this.client.publish(topic, JSON.stringify(message), {qos : 2}, (error, result) => {
                if(error) {
                    resolve(false)
                }else {
                    resolve(true)
                }
            })
        })

        
    }

    private chargeAct(deviceId:string, action:1|2|3, params:ChargeParams) {
        let str = '0008'
        str += numToHex(params.portNo, 2)
        str += numToHex(params.orderId, 22)
        str += numToHex(params.strategyType, 2)
        str += numToHex(action, 2)
        str += numToHex((params.amount || 0) * 100, 8)
        str += strToHex(params.openDoorPassword || '0', 8)

        return str
    }

    charge(deviceId:string, params:ChargeParams) {
        return this.send(deviceId, 1, this.chargeTopic, this.chargeAct(deviceId, 1, params))
    }

    addCharge(deviceId:string, params:ChargeParams) {
        return this.send(deviceId, 1, this.addChargeTopic, this.chargeAct(deviceId, 2, params))
    }

    stopCharge(deviceId:string, params:ChargeParams) {
        return this.send(deviceId, 1, this.stopChargeTopic, this.chargeAct(deviceId, 3, params))
    }


}
